<?php
/**
 * PHP Framework emission class registrar class
 *
 * @author Andrew <andrew@vitche.com>
 * @author Frozen Rain <frozenrain@mail.ru>
 **/

// TODO: Rename to "CodeRegistrar"
class ClassRegistrar {

    private static $_items = array();

    private static $_uri = null;

    public function __construct() {

        ClassRegistrar::$_uri = Configuration::get('Framework.Core.Reflection.Emit.ClassRegistrar._uri');
    }

    public static function add($namespace, $class) {

        // Create namespace definition if missing
        if (!isset(ClassRegistrar::$_items[$namespace])) {
            ClassRegistrar::$_items[$namespace] = array();
        }

        // Create class definition if missing
        if (!isset(ClassRegistrar::$_items[$namespace][$class])) {

            $path = NamingConventionMapper::namespaceToFolder($namespace);

            if (empty($class)) {

                // For namespace declaration
                $path .= "/include.php";
            } else {

                // For class
                $path .= "/" . $class . ".php";
            }

            ClassRegistrar::$_items[$namespace][$class]['path'] = $path;
        }
    }

    public static function attach($namespace, $class) {

        ClassRegistrar::add($namespace, $class);

        $strPath = ClassRegistrar::$_items[$namespace][$class]['path'];
        if (file_exists($strPath)) {

            if (!class_exists($class, false)) {
                require_once($strPath);
            }
        } else {

            // Check to avoid nested emission
            // TODO: Find how the nested emission may be used
            if (!isset($_REQUEST['namespace']) && !isset($_REQUEST['class'])) {

                // Force loading instance settings
                $ClassRegistrar = new ClassRegistrar();

                $folder = NamingConventionMapper::namespaceToFolder($namespace);
                $path = '';
                if (empty($class)) {

                    $path .= $folder . '/include.php';
                } else {
                    $path .= $folder . '/' . $class . '.php';
                }

                // Try loading class from the remote emitter
                $uri = ClassRegistrar::$_uri . '?EmitWebService/get&namespace=' . $namespace . '&class=' . $class;
                $data = file_get_contents($uri);

                // Whether file data was received
                if (!empty($data)) {

                    // Save file data
                    ClassRegistrar::mk_dir($folder);
                    file_put_contents($path, $data);

                    if (!class_exists($class, false)) {

                        // Try to include file again
                        require_once($path);
                    }
                }
            }
        }
    }

    // TODO: Refactor. Move to a separate path
    private static function mk_dir($path, $rights = 0777) {

        if (!@is_dir($path)) {
            $folder_path = array($path);
        } else {
            return;
        }

        while(!@is_dir(dirname(end($folder_path)))
            && dirname(end($folder_path)) != '/'
            && dirname(end($folder_path)) != '.'
            && dirname(end($folder_path)) != '') {
            array_push($folder_path, dirname(end($folder_path)));
        }

        while($parent_folder_path = array_pop($folder_path)) {
            if(!@mkdir($parent_folder_path, $rights)) {
                user_error("Can't create folder \"$parent_folder_path\".\n");
            }
        }
    }

    public static function get($namespace, $class) {

        return file_get_contents(ClassRegistrar::$_items[$namespace][$class]['path']);
    }

    public static function getList() {
        return ClassRegistrar::$_items;
    }
}
?>